#include "Keyboard_PS2.h"
#include "stdio.h"

/************************************************************************/
/*
PB14接PS2的CLK
PB15接PS2的DATA
*/
/************************************************************************/




//键盘实例
Keyboard_PS2 keyboard_ps2;

Keyboard_PS2* getKeyboard(){
	return &keyboard_ps2;
}



extern "C" {
	//BP0 - CLK
	void EXTI0_IRQHandler(){
	
		if(EXTI_GetITStatus(EXTI_Line0)!=RESET){
			EXTI_ClearITPendingBit(EXTI_Line0);
			keyboard_ps2.clkEvent();
		}
		
	}
}





//扫描码转ascii
//未按shift
const u8 unshifted[][2] =
{
	0x1c,'a',
	0x32,'b',
	0x21,'c',
	0x23,'d',
	0x24,'e',
	0x2b,'f',
	0x34,'g',
	0x33,'h',
	0x43,'i',
	0x3b,'j',
	0x42,'k',
	0x4b,'l',
	0x3a,'m',
	0x31,'n',
	0x44,'o',
	0x4d,'p',
	0x15,'q',
	0x2d,'r',
	0x1b,'s',
	0x2c,'t',
	0x3c,'u',
	0x2a,'v',
	0x1d,'w',
	0x22,'x',
	0x35,'y',
	0x1a,'z',
	0x45,'0',
	0x16,'1',
	0x1e,'2',
	0x26,'3',
	0x25,'4',
	0x2e,'5',
	0x36,'6',
	0x3d,'7',
	0x3e,'8',
	0x46,'9',
	0x0e,'`',
	0x4e,'-',
	0x55,'=',
	0x5d,'\\',
	0x66,'\b',
	0x29,0x20,
	0x0d,'\t',
	0x5a,'\n',
	0x76,0x1b,
	0x54,'[',
	0x7c,'*',
	0x7b,'-',
	0x79,'+',
	0x71,'.',
	0x70,'0',
	0x69,'1',
	0x72,'2',
	0x7a,'3',
	0x6b,'4',
	0x73,'5',
	0x74,'6',
	0x6c,'7',
	0x75,'8',
	0x7d,'9',
	0x5b,']',
	0x4c,';',
	0x52,'\'',
	0x41,',',
	0x49,'.',
	0x4a,'/',
};


//按下shift
const u8 shifted[][2] =
{
	0x1c,'A',
	0x32,'B',
	0x21,'C',
	0x23,'D',
	0x24,'E',
	0x2b,'F',
	0x34,'G',
	0x33,'H',
	0x43,'I',
	0x3b,'J',
	0x42,'K',
	0x4b,'L',
	0x3a,'M',
	0x31,'N',
	0x44,'O',
	0x4d,'P',
	0x15,'Q',
	0x2d,'R',
	0x1b,'S',
	0x2c,'T',
	0x3c,'U',
	0x2a,'V',
	0x1d,'W',
	0x22,'X',
	0x35,'Y',
	0x1a,'Z',
	0x45,')',
	0x16,'!',
	0x1e,'@',
	0x26,'#',
	0x25,'$',
	0x2e,'%',
	0x36,'^',
	0x3d,'&',
	0x3e,'*',
	0x46,'(',
	0x0e,'~',
	0x4e,'_',
	0x55,'+',
	0x5d,'|',
	0x66,'\b',
	0x29,0x20,
	0x0d,'\t',
	0x5a,'\n',
	0x76,0x1b,
	0x54,'{',
	0x7c,'*',
	0x7b,'-',
	0x79,'+',
	0x71,'.',
	0x70,'0',
	0x69,'1',
	0x72,'2',
	0x7a,'3',
	0x6b,'4',
	0x73,'5',
	0x74,'6',
	0x6c,'7',
	0x75,'8',
	0x7d,'9',
	0x5b,'}',
	0x4c,':',
	0x52,'"',
	0x41,'<',
	0x49,'>',
	0x4a,'?',
};


//up为通断码标志,shift为shift键按下标志
vu8 kb_up = 0, kb_shift = 0;

//ctrl和alt按下标志
vu8 kb_alt=0;
vu8 kb_ctrl=0;




//解码函数,返回1表示keydown,0表示keyup，2表示特殊键   key:返回对应的键ascii码，特殊键时key为扫描码
u8 kb_decode(u8 scancode, vu8* key)
{
	u8 i;

	if (!kb_up)          //kb_up为0是通码, 按键按下响应
	{
		switch (scancode)		//扫描码解释
		{
		case 0xF0:      //键盘释放,随后一个字节是断码
			kb_up = 1;      //设置断码标志
			break;

		//忽略e0 e1
		case 0xe0:
		case 0xe1:
			break;

		case 0x12:      //左shift按下
			kb_shift = 1;
			break;
		case 0x59:      //右shift按下
			kb_shift = 1;
			break;

		case 0x11:		//ALT键按下
			kb_alt=1;
			break;

		case 0x14:		//Ctrl键按下
			kb_ctrl=1;
			break;

		case 0x58:  //caps键
			kb_shift = (kb_shift == 0) ? 1 : 0;
			break;

		case 0x66: //backspace					
			*key = '\b';
			return 1;

		case 0x5a:	//回车键
			*key = '\n';
			return 1;

		default:
			if (!kb_shift)   //shift未按下
			{
				//从unshifted表译码
				for (i = 0; unshifted[i][0] != scancode&&unshifted[i][0]; i++);
				if (unshifted[i][0] == scancode)
				{
					*key = unshifted[i][1];
				}
				else{
					*key=scancode;		//在表中找不到，特殊键
					return 2;		
				}
			}
			else         //shift按下
			{
				//从shifted表译码
				for (i = 0; shifted[i][0] != scancode&&shifted[i][0]; i++);
				if (shifted[i][0] == scancode)
				{
					*key = shifted[i][1];
				}
				else{
					*key=scancode;	//在表中找不到，特殊键
					return 2;		
				}
			}
			return 1;
		}
	}
	else                   //断码，即按钮弹起响应
	{
		kb_up = 0;               //复位断码标志 
		switch (scancode)    //检查shift键释放
		{
		case 0x12:          //左shift
			kb_shift = 0;
			break;
		case 0x59:          //右shift  
			kb_shift = 0;
			break;

		case 0x11:		//ALT键按下
			kb_alt=0;
			break;

		case 0x14:		//Ctrl键按下
			kb_ctrl=0;
			break;

		default:
			break;
		}
	}

	return 0;
}




Keyboard_PS2::Keyboard_PS2()
{
	kbBitCnt = 0;
	kbData = 0;
	kbKey = 0;
	m_pListener = 0;

	m_pGPIOB = new es_Gpio(GPIOB);
}

Keyboard_PS2::~Keyboard_PS2()
{
	delete m_pGPIOB;
}


void Keyboard_PS2::Init(KeyboardEventListener* pListener)
{
	this->m_pListener = pListener;
//bp0-clk
	//bp10-data
	m_pGPIOB->pinMode(p0, inPU, TRUE);
	m_pGPIOB->pinMode(p10, inPU);
}



//键盘时钟事件
void Keyboard_PS2::clkEvent()
{
	vu8 data = m_pGPIOB->pinInValue(p10);	//PB10键盘DATA

	if (kbBitCnt == 0) {	//起始位检查
		kbData = 0;
		kbBitCnt++;
		return;
	}

	if (kbBitCnt < 9) {	//1-8		注意低位在前				
		u8 b = data << (kbBitCnt - 1);
		kbData = kbData | b;

		kbBitCnt++;
		return;
	}

	if (kbBitCnt == 9) {	//P			
		kbBitCnt++;
		return;
	}

	if (kbBitCnt == 10) {		//停止位
								//解码
		u8 keyState = kb_decode(kbData, &kbKey);

		if (keyState)		//非0，keydown事件，为1表示普通ascii键，2表示特殊键
		{
			//通知观察者
			if (m_pListener != NULL){
				KeyEventArgs e;
				e.keyType=(keyState==1?NORMAL_KEY:FUNCTION_KEY);
				e.key=kbKey;
				e.shift_down=kb_shift;
				e.ctrl_down=kb_ctrl;
				e.alt_down=kb_alt;

				this->m_pListener->OnKeyPress(e);
			}				
		}

		kbBitCnt = 0;
	}
}
